﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Design;
using System.Drawing;
using System.Diagnostics;
using UIDesigner.Properties;

namespace UIControl
{
    public class ToolBoxCtrl : Panel
    {
        private List<ToolboxItem> m_itemList = new List<ToolboxItem>();
        private ToolboxItem m_theActiveItem = null;
        private ToolboxItem m_theHoverItem = null;
        private ToolboxItem m_theToolPointer = new ToolboxItem();
        private bool m_isMouseDown = false;
        private const int m_nItemHeight = 20;
        private float m_nMaxWidth = 0;
        private int m_nVisibleTop = 0;

        public ToolBoxCtrl()
            : base()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint
                | ControlStyles.ContainerControl
                | ControlStyles.ResizeRedraw
                | ControlStyles.StandardClick
                | ControlStyles.Selectable
                | ControlStyles.StandardDoubleClick, true);

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            m_theToolPointer.DisplayName = PointerName;
            m_theToolPointer.Bitmap = Resources.Pointer;
            m_itemList.Add(m_theToolPointer);
            m_theActiveItem = m_theToolPointer;
        }

        public ToolboxItem Pointer
        {
            get
            {
                return m_theToolPointer;
            }
        }

        public string PointerName
        {
            get
            {
                return "<Pointer>";
            }
        }

        public void AddItem(Type type)
        {
            ToolboxItem item = new ToolboxItem(type);
            m_itemList.Add(item);
            if (this.Visible && (this.Handle != null))
            {
                this.Refresh();
            }
        }

        public Image GetPreviewImage(Type type)
        {
            Bitmap img = null;
            try
            {
                ToolboxItem item = new ToolboxItem(type);
                img = item.Bitmap;
            }
            catch
            {
            }
            return img;
        }

        public List<ToolboxItem> Items
        {
            get
            {
                return m_itemList;
            }
        }

        public ToolboxItem SelectedItem
        {
            get
            {
                return m_theActiveItem;
            }
            set
            {
                m_theActiveItem = null;
                if (value == null)
                {
                    m_theActiveItem = m_theToolPointer;
                }
                else
                {
                    foreach (ToolboxItem item in m_itemList)
                    {
                        if (item == value)
                        {
                            m_theActiveItem = item;
                            break;
                        }
                    }
                }
                if (m_theActiveItem == null)
                {
                    m_theActiveItem = m_theToolPointer;
                }
                this.Invalidate();
            }
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            int nHeight = Math.Max(m_itemList.Count * m_nItemHeight, ClientSize.Height);
            Bitmap img = new Bitmap(ClientSize.Width, nHeight);
            Graphics g = Graphics.FromImage(img);
            g.Clear(Color.White);//Color.FromArgb(230, 227, 211));
            int nTop = 0;
            SolidBrush brushSelected = new SolidBrush(Color.FromArgb(193, 210, 238));
            SolidBrush brushOver = new SolidBrush(Color.FromArgb(225, 230, 232));
            StringFormat format = new StringFormat();
            format.FormatFlags = StringFormatFlags.LineLimit;

            foreach (ToolboxItem item in m_itemList)
            {
                if (item == m_theActiveItem)
                {
                    g.FillRectangle(brushSelected, 0, nTop, ClientSize.Width, m_nItemHeight);
                    g.DrawRectangle(Pens.Silver, 0, nTop, ClientSize.Width, m_nItemHeight);
                }
                else if (item == m_theHoverItem)
                {
                    g.FillRectangle(brushOver, 0, nTop, ClientSize.Width, m_nItemHeight);
                    g.DrawRectangle(Pens.Silver, 0, nTop, ClientSize.Width, m_nItemHeight);
                }
                g.DrawImage(item.Bitmap, 3, nTop + 2);
                SizeF size = g.MeasureString(item.DisplayName, Font);
                m_nMaxWidth = Math.Max(m_nMaxWidth, size.Width);
                g.DrawString(item.DisplayName, Font, Brushes.Black, item.Bitmap.Width + 6, nTop + 3, format);

                nTop += m_nItemHeight;
            }
            format.Dispose();
            brushSelected.Dispose();
            brushOver.Dispose();
            g.Dispose();
            e.Graphics.DrawImage(img, 0, -m_nVisibleTop);
            img.Dispose();
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            m_theHoverItem = null;
            base.OnMouseLeave(e);
            this.Invalidate();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            m_theHoverItem = null;
            if (m_isMouseDown)
            {
                if (m_theActiveItem != null)
                {
                    DoDragDrop(m_theActiveItem, DragDropEffects.Copy | DragDropEffects.Move);
                }
                m_isMouseDown = false;
            }
            else
            {
                int nIndex = (e.Y + m_nVisibleTop) / m_nItemHeight;
                if ((nIndex >= 0) && (nIndex < m_itemList.Count))
                {
                    m_theHoverItem = m_itemList[nIndex];
                }
                this.Invalidate();
            }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            this.Focus();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            m_isMouseDown = true;
            m_theActiveItem = null;
            int nIndex = (e.Y + m_nVisibleTop) / m_nItemHeight;
            if ((nIndex >= 0) && (nIndex < m_itemList.Count))
            {
                m_theActiveItem = m_itemList[nIndex];
            }
            this.Invalidate();
            this.Focus();
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            m_isMouseDown = false;
        }

        public override void Refresh()
        {
            m_nVisibleTop = 0;
            base.Refresh();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            //base.OnMouseWheel(e);
            int nMaxHeight = m_itemList.Count * m_nItemHeight;
            int nDelta = (e.Delta / 120) * m_nItemHeight;
            if (m_nVisibleTop - nDelta <= 0)
            {
                m_nVisibleTop = 0;
            }
            else if (m_nVisibleTop - nDelta + this.ClientSize.Height > nMaxHeight)
            {
                m_nVisibleTop = nMaxHeight - this.ClientSize.Height;
            }
            else
            {
                m_nVisibleTop -= nDelta;
            }
            if (m_nVisibleTop < 0)
            {
                m_nVisibleTop = 0;
            }
            this.Invalidate();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            m_nVisibleTop = 0;
            this.Invalidate();
        }

    }
}
